package com.mock.water.core.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.mock.water.modules.system.user.entity.UserEntity;
import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;

/**
 * @Author ifredomvip@gmail.com
 * @Date 2022/11/9 11:14
 */

@Component
@Slf4j
@ConfigurationProperties(prefix = "jwt")
public class JwtUtils {

    /**
     * 秘密
     */
    public static String secret;
    /**
     * 到期时间
     */
    public static long expire;
    /**
     * 请求头中的字段
     */
    public static String tokenHeader;
    /**
     * 请求头前缀
     */
    public static String tokenPrefix;

    /**
     * 创建令牌
     * 使用用户id以及角色id
     *
     * @param username 用户
     * @return {@link String}
     */
    public static String generateToken(String username, String secret) {
        Date now = new Date();
        Date date = new Date(now.getTime() + expire * 1000);
        Algorithm algorithm = Algorithm.HMAC256(secret);

        return JWT.create()
                .withClaim("username", username)
//                .withClaim("roleId", 1)
                .withExpiresAt(date)
                .sign(algorithm);
    }

    /**
     * 验证
     * token中已经包含 Payload 信息（username），此处进行校验不需要再传入username
     *
     * @param token    令牌
     * @param username 用户名
     * @param secret   秘密
     * @return boolean
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).build();
            verifier.verify(token);

            log.info("token验证通过");
            return true;
        } catch (Exception e) {
            log.error("token 无效 {}", e.getMessage());
            return false;
        }
    }

    /**
     * token是否过期
     *
     * @return true：过期
     */
    public static boolean isExpired(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return System.currentTimeMillis() > jwt.getExpiresAt().getTime();
    }

    /**
     * 刷新token的有效期
     *
     * @param token token
     * @param secret 密钥
     * @return 签名Id
     */
    public static String refreshTokenExpired(String token, String secret) {
        // 解析token
        DecodedJWT jwt = JWT.decode(token);
        // 获取token的参数信息
        Map<String, Claim> claims = jwt.getClaims();

        try {
            Date date = new Date(System.currentTimeMillis() + expire);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTCreator.Builder builder = JWT.create().withExpiresAt(date);
            for (Map.Entry<String, Claim> entry : claims.entrySet()) {
                builder.withClaim(entry.getKey(), entry.getValue().asString());
            }
            return builder.sign(algorithm);
        } catch (JWTCreationException e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 从 token中获取用户id
     *
     * @return token中包含的用户id
     */
    public static String getClaim(String token, String claim) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(claim).asString();
        } catch (JWTDecodeException e) {
            log.error("error：{}", e.getMessage());
            return null;
        }
    }

    public static String getUserName(String token) {

        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            log.error("error：{}", e.getMessage());
            return null;
        }
    }


    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public void setExpire(long expire) {
        this.expire = expire;
    }

    public long getExpire() {
        return expire;
    }
}
